from logging import Handler, NOTSET, Logger, CRITICAL

from home_application.models import Records
from datetime import datetime

class LogDBHandler(Handler):
    def __init__(self, level=NOTSET):
        Handler.__init__(self, level)

    def emit(self, record) -> None:
        logs = Records()
        logs.platform = record.platform
        logs.oper_name = record.oper_name
        logs.oper_ip = record.oper_ip
        logs.oper_datetime = datetime.now()
        logs.plat_module = record.plat_module
        logs.oper_method = record.oper_method
        logs.save()


class AuditLogger(Logger):
    """
    自定义日志记录类
    """
    AUDIT_LOGIN = 1      # 登录日志
    AUDIT_OPERATION = 2  # 操作日志
    AUDIT_EXCEPTION = 3  # 异常日志
    AUDIT_UPDATE = 4     # 升级日志
    AUDIT_PERMISSION = 5  # 越权日志

    AUDIT_LOG_TYPE = {
        AUDIT_LOGIN: 'AUDIT_LOGIN',
        AUDIT_OPERATION: 'AUDIT_OPERATION',
        AUDIT_EXCEPTION: 'AUDIT_EXCEPTION',
        AUDIT_UPDATE: 'AUDIT_UPDATE',
        AUDIT_PERMISSION: 'AUDIT_PERMISSION',
    }

    def __int__(self, name, level=NOTSET):
        if not name:
            name = 'app'
        Logger.__init__(self, name, level)

    def loginLog(self, request, result, operation_key, operation_content='', return_message=''):
        '''
        记录与登录相关的日志：登录、登出、次数过多被锁定...
        '''
        self.auditLog(AuditLogger.AUDIT_LOGIN, request, result, operation_key, operation_content, return_message)

    def operationLog(self, request, result, operation_key, operation_content='', return_message=''):
        self.auditLog(AuditLogger.AUDIT_OPERATION, request, result, operation_key, operation_content, return_message)

    def exceptionLog(self, request, operation_key, operation_content='', return_message=''):
        '''
        异常日志
        '''
        self.auditLog(AuditLogger.AUDIT_EXCEPTION, request, False, operation_key, operation_content, return_message)

    def updateLog(self, request, result, operation_key, operation_content='', return_message=''):
        '''
        升级日志
        '''
        self.auditLog(AuditLogger.AUDIT_UPDATE, request, result, operation_key, operation_content, return_message)

    def permissionLog(self, request, result, operation_key, operation_content='', return_message=''):
        '''
        权限日志，如无越权操作。
        '''
        self.auditLog(AuditLogger.AUDIT_PERMISSION, request, result, operation_key, operation_content, return_message)

    def auditLog(self, type, request, result, operation_key, operation_content='', return_message=''):
        """
        供web端记录审计日志
        """
        account = request.session.get('account', '')
        account_id = request.session.get('id', 0)
        if not account:
            if request.user.username:
                account = request.user.username
            else:
                account = 'admin'
        if account_id != 0 and not account_id:
            account_id = request.user.id
        remote_addr = request.META['REMOTE_ADDR']
        self._auditLog(type, account, account_id, remote_addr, result, operation_key, operation_content, return_message)

    def conLog(self, type, account, account_id, remote_addr, result, operation_key, operation_content='',
               return_message=''):
        '''
        供后台程序记录审计日志
        '''
        self._auditLog(type, account, account_id, remote_addr, result, operation_key, operation_content, return_message)

    def cLog(self, operation_key, result=True, operation_content='', type=AUDIT_OPERATION, return_message=''):
        '''
        简单版的后台记录日志的接口
        必要参数：
        1、operation_key：操作码(也即是操作描述)

    可选参数:
        3、result： 操作成功还是失败，true | false
        3、operation_content:日志操作对象，如operation_key为删除帐号，则这里的operation_content就是删除的具体帐号名称
        4、type：日志类型，默认值为操作日志。其他的还有登陆日志(1:AuditLogger.AUDIT_LOGIN)、异常日志(3:AuditLogger.AUDIT_EXCEPTION)、升级日志(4:AuditLogger.AUDIT_UPDATE)
        5、return_message:其他的说明信息，例如调用网络接口后，网络接口可能会返回一些网络信息等。
                    注，5里面记录的内容需要过滤掉一些敏感信息，如后台程序路径、文件名称等
        '''
        self.conLog(type, 'admin', 2, '127.0.0.1', result, operation_key, operation_content, return_message)

    def _auditLog(self, type, account, account_id, remote_addr, result, operation_key, operation_content,
                  return_message):
        """
        如果只记录account_id,而不记录account，则当账号被删除时，就不知道该条日志是哪个账号产生的；
        如果只记录account，而不记录account_id，则当账号被删除后，又创建了一个同名账号，则之前账号的日志就被附加到该账号上
        """
        extra = {}
        extra['account'] = account
        extra['account_id'] = account_id
        extra['remote_addr'] = remote_addr
        if type not in AuditLogger.AUDIT_LOG_TYPE:
            return 'log type is not defined, please user AUDIT_LOGIN, AUDIT_OPERATION, AUDIT_EXCEPTION, AUDIT_UPDATE, or AUDIT_PERMISSION'
        extra['type'] = type
        extra['operation_key'] = operation_key
        extra['operation_content'] = operation_content
        extra['result'] = result
        extra['return_message'] = return_message
        msg = ''
        args = None
        self._log(CRITICAL, msg, args, extra=extra)  # 调用父类函数
